package info.wangyuan.agent.service.event.listener;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import info.wangyuan.agent.common.Enum.Action;
import info.wangyuan.agent.entity.po.KnowledgeBase;
import info.wangyuan.agent.entity.po.KnowledgeSource;
import info.wangyuan.agent.mapper.KnowledgeBaseMapper;
import info.wangyuan.agent.mapper.KnowledgeSourceMapper;
import info.wangyuan.agent.service.event.AgentDeletedEvent;
import info.wangyuan.agent.service.event.KbAndAgentBindsChangedEvent;
import info.wangyuan.agent.utils.FolderMetaUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 监听知识库绑定关系变化事件
 *
 * @author Albert
 * @since 2025-08-18 16:16:28
 */
@Slf4j
@Component
public class FolderMetaEventListener {

    private final KnowledgeSourceMapper ksMapper;
    private final KnowledgeBaseMapper kbMapper;

    public FolderMetaEventListener(KnowledgeSourceMapper ksMapper, KnowledgeBaseMapper kbMapper) {
        this.ksMapper = ksMapper;
        this.kbMapper = kbMapper;
    }

    /**
     * 处理指定知识库的绑定/删除
     */
    @Async
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void onKbAndAgentBindsChanged(KbAndAgentBindsChangedEvent evt) {

        Integer evtAgentId = evt.getAgentId();
        List<KnowledgeBase> evtKbs = evt.getKbs();
        Action evtAction = evt.getAction();

        log.info("[FolderMeta] 同步知识库元数据开始, action={}, agentId={}", evtAction, evtAgentId);

        if (CollUtil.isEmpty(evtKbs)) return;

        switch (evtAction) {

            case ADD -> evtKbs.forEach(kb ->
                    processFolderMeta(kb.getPath(), evtAgentId, true));

            case REMOVE -> evtKbs.forEach(kb ->
                    processFolderMeta(kb.getPath(), evtAgentId, false));

            default -> log.warn("[FolderMeta] 未处理的 action={}, agentId={}", evtAction, evtAgentId);
        }
    }

    /**
     * 根据 Agent ID 清理知识库绑定关系和元数据
     */
    @Async
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void onAgentBindsDeleted(AgentDeletedEvent evt) {

        Integer evtAgentId = evt.getAgentId();

        log.info("[FolderMeta] 清理 Agent 绑定, agentId={}", evtAgentId);

        removeAgentIdFromKbMetadata(evtAgentId);

        ksMapper.delete(Wrappers.lambdaQuery(KnowledgeSource.class)
                .eq(KnowledgeSource::getAgentId, evtAgentId));
    }

    /**
     * 删除指定 Agent 在所有 KB 的元数据绑定
     */
    private void removeAgentIdFromKbMetadata(Integer agentId) {

        List<KnowledgeSource> knowledgeSources = ksMapper.selectList(
                Wrappers.lambdaQuery(KnowledgeSource.class).eq(KnowledgeSource::getAgentId, agentId));

        if (CollUtil.isEmpty(knowledgeSources)) return;

        // 批量查 KnowledgeBase
        Set<Integer> kbIds = knowledgeSources.stream()
                .map(KnowledgeSource::getKnowledgeBaseId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        if (CollUtil.isEmpty(kbIds)) return;

        List<KnowledgeBase> kbs = kbMapper.selectByIds(kbIds);
        if (CollUtil.isEmpty(kbs)) return;

        for (KnowledgeBase kb : kbs) {
            processFolderMeta(kb.getPath(), agentId, false);
        }
    }

    /**
     * 处理元数据增删
     */
    private void processFolderMeta(String path, Integer agentId, boolean add) {
        try {
            Path folderPath = Path.of(path);
            boolean success = add
                    ? FolderMetaUtils.addAgentIdToFolder(folderPath, agentId)
                    : FolderMetaUtils.removeAgentIdFromFolder(folderPath, agentId);

            if (!success) {
                log.error("[FolderMeta] 修改元数据失败, path={}, agentId={}, add={}", path, agentId, add);
            } else {
                log.info("[FolderMeta] 元数据更新成功, path={}, agentId={}, add={}", path, agentId, add);
            }
        } catch (IOException e) {
            log.error("[FolderMeta] 操作异常, path={}, agentId={}, add={}", path, agentId, add, e);
        }
    }
}
